#include "stdafx.h"
#include "JsonAnimation.h"
#include "Core/AssertEx.h"
#include "GameStates/lib_json/json.h"
#include "IReadFile.h"
#include "IWriteFile.h"
#include "Application.h"

namespace JsAnimation {
using namespace irr;
using namespace core;
using namespace io;
const float JsonAnimation::FLOAT_DES = 0.001f;
JsonAnimation::JsonAnimation() 
{
	m_isPause = false;
	m_isEnd = false;
	m_isValid = false;
	m_curAnimTime = 0.0f;
	m_speed = 1.0f;
}

void JsonAnimation::Update(float dt) 
{
	if( m_isEnd ) {
		return;
	}
	if( m_isPause )
	{
		return;
	}

	float realDt = dt * m_speed;
	m_curAnimTime += realDt;

	const Normal2DKey& beginData = m_keyDatas.front();
	if( m_curAnimTime <= beginData.m_keyTime ) {
		m_currentData.m_x = beginData.m_x;
		m_currentData.m_y = beginData.m_y;
		m_currentData.m_alpha = beginData.m_alpha;
		return;
	}


	const Normal2DKey& endData = m_keyDatas.back();
	if( m_curAnimTime >= endData.m_keyTime ) {
		m_currentData.m_x = endData.m_x;
		m_currentData.m_y = endData.m_y;
		m_currentData.m_alpha = endData.m_alpha;
		m_isEnd = true;
		return;
	}

	ASSERT(m_keyDatas.size() >= 2);
	for( int i = 0; i < m_keyDatas.size() - 1; ++i ) {
		const Normal2DKey& firstData = m_keyDatas[i];
		const Normal2DKey& secondData = m_keyDatas[i+1];

		ASSERT(firstData.m_keyTime <= secondData.m_keyTime && "KeyTime must be increase");

		if( (m_curAnimTime >= firstData.m_keyTime - FLOAT_DES )
			&&	(m_curAnimTime <= secondData.m_keyTime + FLOAT_DES) ) {
			m_currentData.m_x = firstData.m_x  + ( (secondData.m_x - firstData.m_x) * (m_curAnimTime - firstData.m_keyTime) / (secondData.m_keyTime - firstData.m_keyTime) );
			m_currentData.m_y = firstData.m_y + ( (secondData.m_y - firstData.m_y) * (m_curAnimTime - firstData.m_keyTime) / (secondData.m_keyTime - firstData.m_keyTime) );
			m_currentData.m_alpha = firstData.m_alpha + ( (secondData.m_alpha - firstData.m_alpha) * (m_curAnimTime - firstData.m_keyTime) / (secondData.m_keyTime - firstData.m_keyTime) );
			m_isValid = true;
			break;
		}
	}

}

JsonAnimationGroup::~JsonAnimationGroup() 
{
	for( AnimMapIter_t it = m_anims.begin(); it != m_anims.end(); ++it ) 
	{
		JsonAnimation* anim = it->second;
		delete anim;
	}
	m_anims.clear();
}

void JsonAnimationGroup::Update(float dt) 
{
	if( m_isPause )
	{
		return;
	}

	for( AnimMapIter_t it = m_anims.begin(); it != m_anims.end(); ++it ) 
	{
		JsonAnimation* anim = it->second;
		anim->Update(dt);
	}
}

void JsonAnimationGroup::SetSpeed( float speed)
{
	for( AnimMapIter_t it = m_anims.begin(); it != m_anims.end(); ++it ) 
	{
		JsonAnimation* anim = it->second;
		anim->SetSpeed(speed);
	}
}

bool JsonAnimationGroup::LoadFromConfig(const char* filename) 
{
	IReadFile* file = Application::instance()->GetDevice()->getFileSystem()->createAndOpenFile(filename);
	ASSERT(file);
	Json::Reader reader;
	Json::Value config;
	reader.parse(file, config, false);
	file->drop();
	file = NULL;

	Json::Value& animsConfig = config["animations"];
	Normal2DKey keyData;
	std::string name;
	for(int i = 0; i < animsConfig.size(); ++i) 
	{
		JsonAnimation* anim = new JsonAnimation;
		Json::Value& animConfig = animsConfig[i];
		name = animConfig["name"].asString();

		Json::Value& keysConfig = animConfig["keys"];
		ASSERT(keysConfig.isArray());
		ASSERT(keysConfig.size() >= 2);

		for(int j = 0; j < keysConfig.size(); ++j) 
		{
			Json::Value& keyConfig = keysConfig[j];

			keyData.m_keyTime = keyConfig["keyTime"].asDouble();
			keyData.m_x = keyConfig["X"].asInt();
			keyData.m_y = keyConfig["Y"].asInt();
			keyData.m_alpha = keyConfig["alpha"].asInt();
			anim->AddKeyData(keyData);
		}

		m_anims.insert(make_pair(name, anim));
	}

	return true;
}

JsonAnimation* JsonAnimationGroup::GetAnimation(const char* animName) {
	AnimMapIter_t it = m_anims.find(animName);
	if( it != m_anims.end() ) {
		return it->second;
	}
	return NULL;
}

void JsonAnimationManager::Update(float dt) {
	for( AnimGroupMapIter_t it = m_animGroups.begin(); it != m_animGroups.end(); ++it ) {
		JsonAnimationGroup* animGroup = it->second;
		animGroup->Update(dt);
	}
}

JsonAnimationGroup* JsonAnimationManager::GetAnimationGroup(const char* animGroupName) {
	AnimGroupMapIter_t it = m_animGroups.find("animationGroupName");
	if( it != m_animGroups.end() ) {
		return it->second;
	}
	return NULL;
}

JsonAnimation* JsonAnimationManager::GetAnimation(const char* animGroupName, const char* animName) {
	JsonAnimationGroup* group = GetAnimationGroup(animGroupName);
	if( group ) 
	{
		return group->GetAnimation(animName);
	}

	return NULL;
}

const Normal2DData* JsonAnimationManager::GetAnimationData(const char* animGroupName, const char* animName) {
	JsonAnimation* anim = GetAnimation(animGroupName, animName);
	if( anim ) 
	{
		return anim->GetCurrentData();
	}

	return NULL;
}

bool JsonAnimationManager::IsAnimationEnd(const char* animGroupName, const char* animName) {
	JsonAnimation* anim = GetAnimation(animGroupName, animName);
	ASSERT(anim);
	if( anim ) 
	{
		return anim->IsAnimationEnd();
	}

	return false;
}

bool JsonAnimationManager::CreateNewAnimationGroup(const char* groupName) {
	ASSERT(groupName);
	std::string groupNameStr = groupName;
	std::string groupFileName  = groupNameStr;
#ifdef TEST_JSON
	groupFileName += "C:/";
#endif
	groupFileName += groupName;
	groupFileName += ".json";
	
	JsonAnimationGroup* animGroup = new JsonAnimationGroup;
	if( !animGroup->LoadFromConfig(groupFileName.c_str()) ) {
		return false;
	}
	
	m_animGroups.insert(make_pair(groupName, animGroup));

	return true;
}

}